package cc.rengu.igas.channel.xmup.core.packswitch;

import cc.rengu.igas.channel.xmup.common.constant.XmupConfigConstant;
import cc.rengu.igas.channel.xmup.common.constant.XmupParamConstant;
import cc.rengu.igas.channel.xmup.common.constant.XmupTreeNodeConstant;
import cc.rengu.igas.channel.xmup.common.enums.RespCodeEnum;
import cc.rengu.igas.channel.xmup.common.util.XmupSecurityUtil;
import cc.rengu.jradp.packetswitch.IncomingPackSwitchImpl;
import cc.rengu.jradp.packetswitch.OutgoingPackSwitchImpl;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.CertInfoMapper;
import cc.rengu.oltp.service.common.dao.SecPlanInfoMapper;
import cc.rengu.oltp.service.common.dao.SrcChannelInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.CertInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SecPlanInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SrcChannelInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.RSAUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;

import java.net.URLDecoder;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.*;

/**
 * 银联全渠道通讯报文解包前后、组前包后实现类
 * Created by 王成 on 2018/12/27.
 */
public class XmupServerPackSwitch implements IncomingPackSwitchImpl, OutgoingPackSwitchImpl {

    @Override
    public byte[] beforeInComPackSwitch(byte[] bytes) throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        /*根据url服务名转换交易码*/
        String serverUrl = xmlTreeUtil.getXmlTreeStringValue("_MESSAGEHEAD/@server_url");
        int lastIndex = serverUrl.lastIndexOf("/");
        String notifyUrl = serverUrl.substring(0, lastIndex);
        SysParamService sysParamService = new SysParamServiceImpl();
        List<SysParam> sysParamList = sysParamService.getSysParamInfo(AppParamConstant.DEFAULT_INSTID, XmupConfigConstant.INST_HOST_URL);
        if (null != sysParamList && sysParamList.size() > 0) {
            Iterator<SysParam> itSysParam = sysParamList.iterator();
            while (itSysParam.hasNext()) {
                SysParam sysParam = itSysParam.next();
                if (notifyUrl.contains(sysParam.getParamValue())) {
                    xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.INST_ID, sysParam.getParamValue());
                    break;
                }
            }
            rglog.error("url<{}>非法通知地址，请联系管理人员!", notifyUrl);
            return new byte[0];
        }
        /* 赋值默认机构、渠道、交易细分 */
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.MSG_SRC_ID, ChannelEnum.XMUP.getChannelType());
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.BIZ_TYPE, XmupParamConstant.DEFAULT_BIZ_TYPE);
        String recvData = new String(bytes);
        if (!recvData.isEmpty()) {
            Map<String, String> recvMap = new HashMap<String, String>();
            recvMap = XmupSecurityUtil.parseJsonString(recvData);
            String charset;
            if (recvMap.get("encoding") != null) {
                charset = recvMap.get("encoding");
                rglog.trace("编码格式为:{}", charset);
            } else {
                rglog.trace("默认UTF-8编码格式...");
                charset = "utf-8";
            }
            String[] kvs = recvData.split("&");
            for (String kv : kvs) {
                String[] tmp = kv.split("=");
                if (tmp.length >= 2) {
                    String key = tmp[0];
                    String value = URLDecoder.decode(tmp[1], charset);
                    recvMap.put(key, value);
                }
            }
            /* 获取通道配置信息 */
            String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
            SrcChannelInfoMapper srcChannelInfoMapper = new SrcChannelInfoMapperImpl();
            SrcChannelInfo srcChannelInfo = srcChannelInfoMapper.selectSrcChannelInfoByPrimaryKey(instId, ChannelEnum.XMUP.getChannelType(), "*");
            if (null == srcChannelInfo) {
                rglog.error("获取渠道<{}>配置信息失败!", ChannelEnum.XMUP.getChannelType());
                throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
            }
            xmlTreeUtil.setXmlTreeObjectValue(XmupTreeNodeConstant.SRC_CHANNEL_INFO, srcChannelInfo);
            /* 根据通道安全计划获取安全计划 */
            SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
            List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(instId, srcChannelInfo.getSecPlanId());
            if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
                xmlTreeUtil.setXmlTreeStringValue(XmupTreeNodeConstant.SEC_PLAN_INFO_LIST, JSON.toJSONString(secPlanInfoList));
                /* 获取敏感信息加密证书 */
                Optional<SecPlanInfo> checkSignSecPlanOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(XmupParamConstant.VERIFY_CERT_TYPE)).findFirst();
                if (checkSignSecPlanOpt.isPresent()) {
                    CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                    CertInfo certInfo = certInfoMapper.selectCertInfoByPrimaryKey(checkSignSecPlanOpt.get().getSecPlanId() + checkSignSecPlanOpt.get().getSecPlanType());
                    /* 验证签名 */
                    if (XmupSecurityUtil.verifySign(XmupSecurityUtil.covertResultMap2String(recvMap), certInfo.getCertValue())) {
                        rglog.info("签名验证成功!");
                        return XmupSecurityUtil.covertResultMap2String(recvMap).getBytes();
                    } else {
                        rglog.error("签名验证失败!");
                        return new byte[0];
                    }
                }
            }
        }
        return bytes;
    }

    @Override
    public int afterInComPackSwitch() throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String txnType = xmlTreeUtil.getXmlTreeStringValue("xmupTxnType");
        String txnSubType = xmlTreeUtil.getXmlTreeStringValue("txnSubType");

        //todo:需要去完成交易码的配置
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, "T00CH000");

        return 0;
    }

    @Override
    public int beforeOutgoPackSwitch() throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/Content-Type", "application/x-www-form-urlencoded");
        return 0;
    }

    @Override
    public byte[] afterOutgoPackSwitch(byte[] bytes) throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String content = new String(bytes);
        rglog.debug("未签名报文：{}", content);
        if (!content.isEmpty()) {
            /* 获取敏感信息加密证书 */
            String secPlanInfoListString = xmlTreeUtil.getXmlTreeStringValue(XmupTreeNodeConstant.SEC_PLAN_INFO_LIST);
            List<SecPlanInfo> secPlanInfoList = JSONArray.parseArray(secPlanInfoListString, SecPlanInfo.class);
            Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(XmupParamConstant.SIGN_CERT_TYPE)).findFirst();
            if (secPlanInfoOpt.isPresent()) {
                CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                CertInfo certInfo = certInfoMapper.selectCertInfoByPrimaryKey(secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
                /* 加签 */
                String signData = null;
                List<String> aliasList = RSAUtil.getCertAliasFromPfxCertFile(certInfo.getCertSavePath(), certInfo.getCertPassword());
                PrivateKey privateKey = RSAUtil.getPrivateKeyFromPfxCertFile(certInfo.getCertSavePath(), aliasList.get(0), certInfo.getCertPassword());
                PublicKey publicKey = RSAUtil.getPublicKeyFromPfxCertFile(certInfo.getCertSavePath(), aliasList.get(0), certInfo.getCertPassword());
                signData = XmupSecurityUtil.sign(content, privateKey, publicKey);

                return signData.getBytes();
            }
        }
        return bytes;
    }
}
